package org.linlinjava.litemall.admin.service;

import com.github.pagehelper.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.linlinjava.litemall.admin.task.ActivityStartTask;
import org.linlinjava.litemall.admin.vo.ActivityListVo;
import org.linlinjava.litemall.core.qcode.QCodeService;
import org.linlinjava.litemall.core.task.TaskService;
import org.linlinjava.litemall.core.util.CommonUtils;
import org.linlinjava.litemall.core.util.DateTimeUtil;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.core.util.TimeUtils;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.domain.dto.LitemallActivityDetailDto;
import org.linlinjava.litemall.db.domain.vo.LitemallActivityCreateVo;
import org.linlinjava.litemall.db.domain.vo.LitemallActivityGrouponEditVo;
import org.linlinjava.litemall.db.domain.vo.LitemallActivityGrouponVo;
import org.linlinjava.litemall.db.domain.vo.LitemallActivityRulesVo;
import org.linlinjava.litemall.db.service.*;
import org.linlinjava.litemall.db.util.TransNoEnum;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static org.linlinjava.litemall.admin.util.AdminResponseCode.GOODS_NAME_EXIST;

@Service
public class AdminActivityListService {

    @Autowired
    private LitemallActivityService litemallActivityService;

    @Autowired
    private ActivityGrouponService activityGrouponService;

    @Autowired
    private LitemallActivityPicService litemallActivityPicService;

    @Autowired
    private LitemallActivityRulesService litemallActivityRulesService;

    @Autowired
    private LitemallActivityContentService contentService;

    @Autowired
    private QCodeService qCodeService;

    @Autowired
    private LitemallAdminService litemallAdminService;

    @Autowired
    private LitemallOrderService litemallOrderService;

    @Autowired
    private TransNoGenerator noGenerator;

    @Autowired
    private TaskService taskService;

    public Object activityList(String title, String startTime, String endTime,
                               LitemallAdmin admin, Integer page, Integer limit,
                               String sort, String order) {
        Page<LitemallActivity> activityList = (Page<LitemallActivity>)
                litemallActivityService.pageQueryActivity(title, startTime, endTime, admin, page, limit, sort, order);

        if (CollectionUtils.isEmpty(activityList)) {
            return ResponseUtil.okList(Collections.emptyList());
        }

        Map<Integer, Map<Byte, LitemallStatistics>> map = Maps.newConcurrentMap();
        for (LitemallActivity activity : activityList) {
            List<LitemallStatistics> litemallStatistics = litemallActivityService.queryStatistics(activity.getType(), activity.getId(), null);
            Map<Byte, LitemallStatistics> statMap = litemallStatistics
                    .stream()
                    .collect(Collectors.toMap(
                            LitemallStatistics::getbType,
                            Function.identity(),
                            (k1, k2) -> TimeUtils.isAfter(k1.getAddTime(), k2.getAddTime()) ? k1 : k2));
            map.put(activity.getId(), statMap);
        }
        Map<String, Object> adminReqMap = Maps.newConcurrentMap();
        List<Integer> adminIds = activityList.stream().map(it -> Integer.valueOf(it.getAddBy())).distinct().collect(Collectors.toList());
        adminReqMap.put("ids", adminIds);
        adminReqMap.put("deleted", LitemallAdmin.NOT_DELETED);
        Map<Integer, String> adminMap = litemallAdminService.findByParams(Collections.singletonList(adminReqMap))
                .stream().collect(Collectors.toMap(LitemallAdmin::getId, LitemallAdmin::getUsername));

        List<ActivityListVo> data = Lists.newArrayList();
        for (LitemallActivity entity : activityList) {
            ActivityListVo vo = new ActivityListVo();
            vo.setTitle(entity.getTitle());
            vo.setId(entity.getId());
            vo.setStartTime(DateTimeUtil.localDateTime2String(entity.getStartTime(), DateTimeUtil.DEFAULT_PATTERN));
            vo.setEndTime(DateTimeUtil.localDateTime2String(entity.getEndTime(), DateTimeUtil.DEFAULT_PATTERN));
            vo.setMusicUrl(entity.getMusicUrl());
            vo.setType(entity.getType());
            vo.setState(entity.getState());
            String userName = "";
            if (MapUtils.isNotEmpty(adminMap)) {
                userName = adminMap.getOrDefault(Integer.valueOf(entity.getAddBy()), "");
            }
            vo.setUserName(userName);

            Map<Byte, LitemallStatistics> byteLongMap = map.get(entity.getId());
            if (MapUtils.isEmpty(byteLongMap)) {
                vo.setViews(0L);
                vo.setApplications(0L);
                vo.setShares(0L);
                vo.setGroupons(0L);
            } else {
                LitemallStatistics views = byteLongMap.getOrDefault(LitemallStatistics.BTypeEnum.VISIT.getCode(), null);
                LitemallStatistics applications = byteLongMap.getOrDefault(LitemallStatistics.BTypeEnum.SING_UP.getCode(), null);
                LitemallStatistics shares = byteLongMap.getOrDefault(LitemallStatistics.BTypeEnum.SHARE.getCode(), null);
                LitemallStatistics groupons = byteLongMap.getOrDefault(LitemallStatistics.BTypeEnum.GROUPON.getCode(), null);

                vo.setViews(views != null ? views.getCount() : 0L);
                vo.setApplications(applications != null ? applications.getCount() : 0L);
                vo.setShares(shares != null ? shares.getCount() : 0L);
                vo.setGroupons(groupons != null ? groupons.getCount() : 0L);
            }

            String url = "http://www.dyundyun.com/ac/?id=" + entity.getId().toString();
            Object qCodeObj = qCodeService.createActivityGrouponShareImage(url);

            Map<String, Object> qCodeMap = (Map<String, Object>) qCodeObj;
            String qCodeUrl = "";
            if (qCodeMap.containsKey("errno") && (int) qCodeMap.get("errno") == 0) {
                if (qCodeMap.containsKey("data")) {
                    qCodeUrl = (String) qCodeMap.get("data");
                }
            }

            vo.setQCode(qCodeUrl);
            data.add(vo);
        }

        Page<ActivityListVo> voPageList = new Page<>();
        voPageList.setPages(activityList.getPages());
        voPageList.setPageNum(activityList.getPageNum());
        voPageList.setPageSize(activityList.getPageSize());
        voPageList.setTotal(activityList.getTotal());
        voPageList.addAll(data);
        return ResponseUtil.okList(voPageList);
    }


    public Object queryActivityDetail(Integer id, Boolean isActAdmin, LitemallAdmin admin) {
        LitemallActivity litemallActivity = litemallActivityService.queryActivity(id, isActAdmin ? null : admin);
        if (Objects.isNull(litemallActivity)) {
            return ResponseUtil.serious();
        }
        Integer activityId = litemallActivity.getId();

        LitemallAdmin dbAdmin = litemallAdminService.findAdmin(Integer.valueOf(litemallActivity.getAddBy()));

        List<LitemallActivityRules> activityRulesList = litemallActivityService.queryActivityRules(Collections.singletonList(activityId));
        List<LitemallActivityGroupon> activityGrouponList = litemallActivityService.queryActivityGroupon(Collections.singletonList(activityId));
        List<LitemallActivityPic> activityPicList = litemallActivityPicService.queryActivityPic(activityId, Collections.emptyList());
        List<LitemallActivityContent> activityContentList = contentService.queryActivityContent(activityId, Collections.emptyList());
        LitemallActivityDetailDto dto = new LitemallActivityDetailDto();
        BeanUtils.copyProperties(litemallActivity, dto);
        String newContacts = "";
        List<String> contactList = activityContentList.stream()
                .filter(it -> LitemallActivityContent.TypeEnum.CONTACTS.getCode().equals(it.getType()))
                .map(it -> CommonUtils.split(it.getContent(), CommonUtils.SPLIT_SYMBOL2))
                .findFirst().orElse(Collections.emptyList());

        if (!CollectionUtils.isEmpty(contactList)) {
            newContacts = contactList.stream().collect(Collectors.joining("\n"));
        }

        String gameRule = activityContentList.stream()
                .filter(it -> LitemallActivityContent.TypeEnum.GAME_RULE.getCode().equals(it.getType()))
                .map(LitemallActivityContent::getContent).findFirst().orElse("");
        dto.setAddBy(dbAdmin.getUsername());
        dto.setContacts(newContacts);
        dto.setAddress(CollectionUtils.isEmpty(contactList) ? "" : contactList.get(0));
        dto.setContactPhone(CollectionUtils.isEmpty(contactList) ? "" : contactList.get(1));
        dto.setEmail(CollectionUtils.isEmpty(contactList) ? "" : contactList.get(2));
        dto.setGameRule(gameRule);


        dto.setHomePic(activityPicList.stream()
                .filter(it -> LitemallActivityPic.TypeEnum.HOME.getCode().equals(it.getType()))
                .map(LitemallActivityPic::getPicUrl).findFirst().orElse(null));
        dto.setSlideshowPic(activityPicList.stream()
                .filter(it -> LitemallActivityPic.TypeEnum.SLIDESHOW.getCode().equals(it.getType()))
                .map(LitemallActivityPic::getPicUrl).collect(Collectors.toList()));
        // 机构介绍
        List<String> orgIntroducePicList = activityPicList.stream()
                .filter(it -> LitemallActivityPic.TypeEnum.ORG_INTRODUCE.getCode().equals(it.getType()))
                .map(LitemallActivityPic::getPicUrl).collect(Collectors.toList());
        String orgIntroduceText = activityContentList.stream()
                .filter(it -> LitemallActivityContent.TypeEnum.ORG.getCode().equals(it.getType()))
                .map(LitemallActivityContent::getContent).findFirst().orElse("");
        dto.setOrgIntroduce(this.buildIntroduceVo(orgIntroducePicList, orgIntroduceText));

        //活动介绍
        List<String> acIntroducePicList = activityPicList.stream()
                .filter(it -> LitemallActivityPic.TypeEnum.AC_INTRODUCE.getCode().equals(it.getType()))
                .map(LitemallActivityPic::getPicUrl).collect(Collectors.toList());
        String acIntroduceText = activityContentList.stream()
                .filter(it -> LitemallActivityContent.TypeEnum.AC.getCode().equals(it.getType()))
                .map(LitemallActivityContent::getContent).findFirst().orElse("");
        dto.setAcIntroduce(this.buildIntroduceVo(acIntroducePicList, acIntroduceText));

        //奖品介绍
        List<String> goodsIntroducePicList = activityPicList.stream()
                .filter(it -> LitemallActivityPic.TypeEnum.GOODS_INTRODUCE.getCode().equals(it.getType()))
                .map(LitemallActivityPic::getPicUrl).collect(Collectors.toList());
        String goodsIntroduceText = activityContentList.stream()
                .filter(it -> LitemallActivityContent.TypeEnum.GOODS.getCode().equals(it.getType()))
                .map(LitemallActivityContent::getContent).findFirst().orElse("");
        dto.setGoodsIntroduce(this.buildIntroduceVo(goodsIntroducePicList, goodsIntroduceText));

        List<LitemallActivityRulesVo> rulesVoList = Lists.newArrayList();
        for (LitemallActivityRules rules : activityRulesList) {
            LitemallActivityRulesVo rulesVo = new LitemallActivityRulesVo();
            BeanUtils.copyProperties(rules, rulesVo);
            Byte deleted = LitemallActivityRules.NOT_DELETED.equals(rules.getDeleted())
                    ? (byte) 0 : (byte) 1;
            rulesVo.setDeleted(deleted);
            rulesVo.setSubject(rules.getActivityGoodsName());
            rulesVoList.add(rulesVo);
        }

        List<String> subjects = activityRulesList.stream().map(LitemallActivityRules::getActivityGoodsName).distinct().collect(Collectors.toList());

        dto.setRulesList(rulesVoList);
        dto.setSubjects(subjects);
        dto.setActivityGrouponList(activityGrouponList);

        List<LitemallStatistics> statList = litemallActivityService.queryStatistics(litemallActivity.getType(), litemallActivity.getId(), null);

        Map<Byte, LitemallStatistics> statMap = statList
                .stream()
                .collect(Collectors.toMap(
                        LitemallStatistics::getbType,
                        Function.identity(),
                        (k1, k2) -> TimeUtils.isAfter(k1.getAddTime(), k2.getAddTime()) ? k1 : k2));
        LitemallStatistics views = statMap.getOrDefault(LitemallStatistics.BTypeEnum.VISIT.getCode(), null);
        LitemallStatistics applications = statMap.getOrDefault(LitemallStatistics.BTypeEnum.SING_UP.getCode(), null);
        LitemallStatistics shares = statMap.getOrDefault(LitemallStatistics.BTypeEnum.SHARE.getCode(), null);
        LitemallStatistics groupons = statMap.getOrDefault(LitemallStatistics.BTypeEnum.GROUPON.getCode(), null);
        // 浏览数
        dto.setViews(views != null ? views.getCount() : 0L);
        // 报名数
        dto.setApplications(applications != null ? applications.getCount() : 0L);
        // 分享数
        dto.setShares(shares != null ? shares.getCount() : 0L);
        // 成团数
        dto.setGroupons(groupons != null ? groupons.getCount() : 0L);

        return ResponseUtil.ok(dto);
    }

    public LitemallActivityDetailDto.IntroduceVo buildIntroduceVo(List<String> pics, String content) {
        LitemallActivityDetailDto.IntroduceVo vo = new LitemallActivityDetailDto.IntroduceVo();
        vo.setText(content);
        vo.setPics(pics);
        return vo;
    }

    /**
     * 团购活动创建
     *
     * @param vo
     * @return
     */
    @Transactional
    public Object createActivity(LitemallActivityCreateVo vo, LitemallAdmin admin) {
        Object error = validate(vo, Boolean.FALSE);
        if (error != null) {
            return error;
        }

        //活动本体
        LitemallActivity activity = new LitemallActivity();
        buildActivity(activity, vo);
        litemallActivityService.addActivity(activity, admin);

        //活动规则
        Integer activityId = activity.getId();
        List<LitemallActivityRulesVo> rulesList = vo.getRulesList();
        for (LitemallActivityRulesVo rules : rulesList) {
            LitemallActivityRules entity = new LitemallActivityRules();
            BeanUtils.copyProperties(rules, entity);
            if (rules.getDeleted() == (byte) 0) {
                entity.setDeleted(LitemallActivityRules.NOT_DELETED);
            } else {
                entity.setDeleted(LitemallActivityRules.IS_DELETED);
            }
            entity.setActivityGoodsName(rules.getSubject());
            entity.setActivityId(activityId);
            litemallActivityRulesService.addActivityRules(entity, admin);
        }

        //图片
        List<LitemallActivityPic> picList = Lists.newArrayList();
        picList.add(buildPic(vo.getHomePic(), activityId, LitemallActivityPic.TypeEnum.HOME.getCode()));
        picList.addAll(vo.getSlideshowPic().stream().map(it -> buildPic(it, activityId, LitemallActivityPic.TypeEnum.SLIDESHOW.getCode())).collect(Collectors.toList()));

        picList.addAll(vo.getOrgIntroduce().getPics().stream().map(it -> buildPic(it, activityId, LitemallActivityPic.TypeEnum.ORG_INTRODUCE.getCode())).collect(Collectors.toList()));
        picList.addAll(vo.getAcIntroduce().getPics().stream().map(it -> buildPic(it, activityId, LitemallActivityPic.TypeEnum.AC_INTRODUCE.getCode())).collect(Collectors.toList()));
        picList.addAll(vo.getGoodsIntroduce().getPics().stream().map(it -> buildPic(it, activityId, LitemallActivityPic.TypeEnum.GOODS_INTRODUCE.getCode())).collect(Collectors.toList()));

        for (LitemallActivityPic pic : picList) {
            litemallActivityPicService.addActivityPic(pic, admin);
        }

        // 活动文本
        contentService.addActivityContent(this.buildContent(activityId,
                vo.getOrgIntroduce().getText(),
                LitemallActivityContent.TypeEnum.ORG.getCode()), admin);
        contentService.addActivityContent(this.buildContent(activityId,
                vo.getAcIntroduce().getText(),
                LitemallActivityContent.TypeEnum.AC.getCode()), admin);
        contentService.addActivityContent(this.buildContent(activityId,
                vo.getGoodsIntroduce().getText(),
                LitemallActivityContent.TypeEnum.GOODS.getCode()), admin);
        contentService.addActivityContent(this.buildContent(activityId,
                vo.getGameRule(),
                LitemallActivityContent.TypeEnum.GAME_RULE.getCode()), admin);
        contentService.addActivityContent(this.buildContent(activityId,
                CommonUtils.join(CommonUtils.SPLIT_SYMBOL2, vo.getAddress(), vo.getContactPhone(), vo.getEmail()),
                LitemallActivityContent.TypeEnum.CONTACTS.getCode()), admin);

        //设置活动到期自动发布
        LocalDateTime startTime = activity.getStartTime();
        LocalDateTime now = LocalDateTime.now();
        if (startTime.isBefore(now)) {
            taskService.addTask(new ActivityStartTask(activityId, 0L));
        } else {
            long delay = ChronoUnit.MILLIS.between(now, startTime);
            taskService.addTask(new ActivityStartTask(activity.getId(), delay));
        }

        return ResponseUtil.ok();
    }


    /**
     * 团购活动校验
     *
     * @param vo
     * @return
     */
    private Object validate(LitemallActivityCreateVo vo, Boolean tag) {
        if (tag) {
            if (Objects.isNull(vo.getId())) {
                return ResponseUtil.fail(900, "活动id不能为空");
            }
        }
        if (Objects.isNull(vo.getType())) {
            return ResponseUtil.fail(900, "类型不能为空");
        }
        if (StringUtils.isEmpty(vo.getTitle())) {
            return ResponseUtil.fail(900, "标题不能为空");
        }
        if (StringUtils.isEmpty(vo.getPosterTitle())) {
            return ResponseUtil.fail(900, "海报文案不能为空");
        }
        if (StringUtils.isEmpty(vo.getShareTitle())) {
            return ResponseUtil.fail(900, "分享链接文案不能为空");
        }
        if (StringUtils.isEmpty(vo.getTitle())) {
            return ResponseUtil.fail(900, "标题不能为空");
        }
        if (Objects.isNull(vo.getStartTime())) {
            return ResponseUtil.fail(900, "开始时间不能为空");
        }
        if (Objects.isNull(vo.getEndTime())) {
            return ResponseUtil.fail(900, "结束时间不能为空");
        }
        if (!tag) {
            if (StringUtils.isEmpty(vo.getHomePic())) {
                return ResponseUtil.fail(900, "首页图不能为空");
            }
            if (CollectionUtils.isEmpty(vo.getSlideshowPic())) {
                return ResponseUtil.fail(900, "轮播图不能为空");
            }
            if (vo.getOrgIntroduce() == null) {
                return ResponseUtil.fail(900, "活动介绍不能为空");
            }
            if (vo.getAcIntroduce() == null) {
                return ResponseUtil.fail(900, "机构介绍不能为空");
            }
            if (vo.getGoodsIntroduce() == null) {
                return ResponseUtil.fail(900, "奖品介绍不能为空");
            }
            if (StringUtils.isBlank(vo.getAddress())) {
                return ResponseUtil.fail(900, "机构联系地址不能为空");
            }
            if (StringUtils.isBlank(vo.getContactPhone())) {
                return ResponseUtil.fail(900, "机构联系电话不能为空");
            }
            if (litemallActivityService.checkActivityExistByTitle(vo.getTitle())) {
                return ResponseUtil.fail(GOODS_NAME_EXIST, "活动名已经存在");
            }
        }
        if (Objects.isNull(vo.getState())) {
            return ResponseUtil.fail(900, "状态不能为空");
        }
        return null;
    }

    public Object activityGrouponList(Byte userType, String activityId, String subject, String grouponCode, String userName,
                                      Byte state, Integer page, Integer limit, String sort, String order) {
        Page<LitemallActivityGroupon> activityGrouponList = (Page<LitemallActivityGroupon>)
                activityGrouponService.pageQuery(null, Integer.valueOf(activityId), null, userType, null, subject,
                        grouponCode, userName, state, page, limit, sort, order);


        if (CollectionUtils.isEmpty(activityGrouponList)) {
            return ResponseUtil.okList(Collections.emptyList());
        }

        List<LitemallActivityGrouponVo> voList = this.convert2Vo(activityGrouponList, activityId);

        Page<LitemallActivityGrouponVo> voPageList = new Page<>();
        voPageList.setPages(activityGrouponList.getPages());
        voPageList.setPageNum(activityGrouponList.getPageNum());
        voPageList.setPageSize(activityGrouponList.getPageSize());
        voPageList.setTotal(activityGrouponList.getTotal());
        voPageList.addAll(voList);
        return ResponseUtil.okList(voPageList);
    }

    public Object activityGrouponList(Byte userType, String activityId, String subject, String grouponCode, String userName,
                                      Byte state) {
        List<LitemallActivityGroupon> activityGrouponList =
                activityGrouponService.queryListForExport(null, Integer.valueOf(activityId), null, userType, null, subject,
                        grouponCode, userName, state);


        if (CollectionUtils.isEmpty(activityGrouponList)) {
            return ResponseUtil.okList(Collections.emptyList());
        }

        List<LitemallActivityGrouponVo> voList = this.convert2Vo(activityGrouponList, activityId);
        return ResponseUtil.okList(voList);
    }

    private List<LitemallActivityGrouponVo> convert2Vo(List<LitemallActivityGroupon> activityGrouponList, String activityId){
        // 查询订单号和微信支付单号
        List<Integer> orderIds = activityGrouponList
                .stream()
                .map(LitemallActivityGroupon::getOrderId)
                .collect(Collectors.toList());
        Map<Integer, LitemallOrder> orderMap = litemallOrderService.findOrderCodeByIds(orderIds)
                .stream()
                .collect(Collectors.toMap(LitemallOrder::getId, Function.identity()));

        // 查团长的组团科目的上限人数
        List<LitemallActivityGroupon> captainGrouponList = activityGrouponList
                .stream()
                .filter(it -> it.getGrouponId().equals(0))
                .collect(Collectors.toList());

        List<Integer> subjectIds = captainGrouponList
                .stream()
                .map(LitemallActivityGroupon::getSubjectId)
                .distinct()
                .collect(Collectors.toList());

        Map<String, Object> rulesParams = Maps.newConcurrentMap();
        rulesParams.put("activityId", activityId);
        rulesParams.put("subjectIds", subjectIds);
        List<LitemallActivityRules> rulesList = litemallActivityRulesService.findByParam(Collections.singletonList(rulesParams));
        Map<Integer, Integer> rulesMap = rulesList.stream().collect(Collectors.toMap(LitemallActivityRules::getId, LitemallActivityRules::getLimited));

        Map<String, Long> grouponTotal = activityGrouponList
                .stream()
                .filter(it -> LitemallActivityGroupon.PayStateEnum.SUCCESS.getCode().equals(it.getPayState()))
                .collect(Collectors.groupingBy(LitemallActivityGroupon::getGrouponCode, Collectors.counting()));

        Map<String, String> grouponSizeMap = captainGrouponList
                .stream()
                .collect(Collectors.toMap(
                        LitemallActivityGroupon::getGrouponCode,
                        it -> CommonUtils.join("/",
                                grouponTotal.getOrDefault(it.getGrouponCode(), 0L).toString(),
                                rulesMap.getOrDefault(it.getSubjectId(), 0).toString()),
                        (k1, k2) -> k1));


        List<LitemallActivityGrouponVo> voList = Lists.newArrayList();
        for (LitemallActivityGroupon entity : activityGrouponList) {
            LitemallActivityGrouponVo vo = new LitemallActivityGrouponVo();
            BeanUtils.copyProperties(entity, vo);
            if (MapUtils.isNotEmpty(orderMap) && orderMap.containsKey(entity.getOrderId())) {
                LitemallOrder litemallOrder = orderMap.get(entity.getOrderId());
                vo.setOrderCode(litemallOrder.getOrderSn());
                vo.setPayId(litemallOrder.getPayId());
            }
            if (MapUtils.isNotEmpty(grouponSizeMap)
                    && grouponSizeMap.containsKey(entity.getGrouponCode())
                    && LitemallActivityGroupon.PayStateEnum.SUCCESS.getCode().equals(entity.getPayState())) {
                String grouponSize = grouponSizeMap.get(entity.getGrouponCode());
                vo.setGrouponSize(grouponSize);
            }

            voList.add(vo);
        }

        // 拼装该团的团长和团成员信息(成功拼团的)
        Map<String, List<LitemallActivityGrouponVo>> grouponMap = voList
                .stream()
                .filter(it -> LitemallActivityGroupon.StateEnum.SUCCESS.getCode().equals(it.getState()))
                .collect(Collectors.groupingBy(LitemallActivityGrouponVo::getGrouponCode));
        for (LitemallActivityGrouponVo vo : voList) {
            if (grouponMap.containsKey(vo.getGrouponCode())) {
                List<LitemallActivityGrouponVo> subList = grouponMap.get(vo.getGrouponCode());
                List<LitemallActivityGrouponVo.SubGrouponVo> subVoList = Lists.newArrayList();
                for (LitemallActivityGrouponVo sub : subList) {
                    LitemallActivityGrouponVo.SubGrouponVo subVo = new LitemallActivityGrouponVo.SubGrouponVo();
                    BeanUtils.copyProperties(sub, subVo);
                    subVoList.add(subVo);
                }
                vo.setSubVoList(subVoList);
            }
        }
        return voList;
    }

    @Transactional
    public Object updateActivity(LitemallActivityCreateVo vo, Boolean isActAdmin, LitemallAdmin admin) {
        Object error = validate(vo, Boolean.TRUE);
        if (error != null) {
            return error;
        }
        LitemallActivity activity = litemallActivityService.queryActivity(vo.getId(), isActAdmin ? null : admin);
        if (activity == null) {
            if (!isActAdmin) {
                return ResponseUtil.fail(900, "抱歉用户不是管理员无法编辑活动");
            } else {
                return ResponseUtil.fail(900, "抱歉查询不到该有效活动");
            }
        }
        if (LitemallActivity.StateEnum.TIME_OUT.getCode().equals(activity.getState())) {
            return ResponseUtil.fail(900, "发布中或到期下线活动不可编辑");
        }
        buildActivity(activity, vo);
        litemallActivityService.updateActivityById(activity, admin);

        //活动规则
        Integer activityId = activity.getId();
        List<LitemallActivityRules> dbRules = litemallActivityRulesService.findByActivityId(activityId);
        List<Integer> notDeleteIds = Lists.newArrayList();
        List<LitemallActivityRulesVo> rulesList = vo.getRulesList();
        for (LitemallActivityRulesVo rules : rulesList) {
            LitemallActivityRules entity = new LitemallActivityRules();
            BeanUtils.copyProperties(rules, entity);
            entity.setActivityGoodsName(rules.getSubject());
            if (entity.getId() != null) {
                notDeleteIds.add(entity.getId());
                litemallActivityRulesService.updateById(entity, admin);
            } else {
                entity.setActivityId(activityId);
                litemallActivityRulesService.addActivityRules(entity, admin);
            }
        }
        for (LitemallActivityRules dbRule : dbRules) {
            if (!notDeleteIds.contains(dbRule.getId())) {
                litemallActivityRulesService.deleteById(dbRule.getId());
            }
        }

        //图片
        List<LitemallActivityPic> exList = litemallActivityPicService.queryActivityPic(activity.getId(), Collections.emptyList());
        for (LitemallActivityPic pic : exList) {
            litemallActivityPicService.deleteById(pic.getId());
        }
        List<LitemallActivityPic> picList = Lists.newArrayList();
        picList.add(buildPic(vo.getHomePic(), activityId, LitemallActivityPic.TypeEnum.HOME.getCode()));
        picList.addAll(vo.getSlideshowPic().stream()
                .map(it -> buildPic(it, activityId, LitemallActivityPic.TypeEnum.SLIDESHOW.getCode()))
                .collect(Collectors.toList()));
        picList.addAll(vo.getOrgIntroduce().getPics().stream()
                .map(it -> buildPic(it, activityId, LitemallActivityPic.TypeEnum.ORG_INTRODUCE.getCode()))
                .collect(Collectors.toList()));
        picList.addAll(vo.getAcIntroduce().getPics().stream()
                .map(it -> buildPic(it, activityId, LitemallActivityPic.TypeEnum.AC_INTRODUCE.getCode()))
                .collect(Collectors.toList()));
        picList.addAll(vo.getGoodsIntroduce().getPics().stream()
                .map(it -> buildPic(it, activityId, LitemallActivityPic.TypeEnum.GOODS_INTRODUCE.getCode()))
                .collect(Collectors.toList()));

        for (LitemallActivityPic pic : picList) {
            litemallActivityPicService.addActivityPic(pic, admin);
        }

        // 活动文本
        contentService.update(this.buildContent(activityId,
                vo.getOrgIntroduce().getText(),
                LitemallActivityContent.TypeEnum.ORG.getCode()), admin);

        contentService.update(this.buildContent(activityId,
                vo.getAcIntroduce().getText(),
                LitemallActivityContent.TypeEnum.AC.getCode()), admin);

        contentService.update(this.buildContent(activityId,
                vo.getGoodsIntroduce().getText(),
                LitemallActivityContent.TypeEnum.GOODS.getCode()), admin);

        contentService.update(this.buildContent(activityId,
                vo.getGameRule(),
                LitemallActivityContent.TypeEnum.GAME_RULE.getCode()), admin);

        if (StringUtils.isNotBlank(vo.getAddress())
                || StringUtils.isNotBlank(vo.getContactPhone())
                || StringUtils.isNotBlank(vo.getEmail())) {
            LitemallActivityContent content = this.buildContent(activityId,
                    CommonUtils.join(CommonUtils.SPLIT_SYMBOL2, vo.getAddress(), vo.getContactPhone(), vo.getEmail()),
                    LitemallActivityContent.TypeEnum.CONTACTS.getCode());
            contentService.update(content, admin);
        }

        LocalDateTime startTime = activity.getStartTime();
        LocalDateTime now = LocalDateTime.now();
        if (startTime.isBefore(now)) {
            taskService.addTask(new ActivityStartTask(activityId, 0L));
        } else {
            long delay = ChronoUnit.MILLIS.between(now, startTime);
            taskService.addTask(new ActivityStartTask(activity.getId(), delay));
        }
        return ResponseUtil.ok();
    }

    public Object changeState(LitemallActivityCreateVo vo, Boolean isAdmin, LitemallAdmin admin) {
        if (vo.getId() == null || StringUtils.isBlank(vo.getState())) {
            return ResponseUtil.fail(900, "活动id和状态不能为空");
        }
        LitemallActivity activity = litemallActivityService.queryActivity(vo.getId(), isAdmin ? null : admin);
        if (activity == null) {
            return ResponseUtil.fail(900, "查询不到活动");
        }
        if (LitemallActivity.StateEnum.TIME_OUT.getCode().equals(activity.getState())) {
            return ResponseUtil.fail(900, "活动已过期");
        }
        Byte bState = Byte.valueOf(vo.getState());
        //目前活动是未发布，允许变更为发布或手动下线
        if (LitemallActivity.StateEnum.TO_BE_ISSUE.getCode().equals(activity.getState())
                && (LitemallActivity.StateEnum.STOP_FORCING.getCode().equals(bState)
                || LitemallActivity.StateEnum.ISSUING.getCode().equals(bState))) {
            activity.setState(bState);
            litemallActivityService.updateActivityById(activity, admin);
        }
        //目前活动是发布中，允许手动下线
        else if (LitemallActivity.StateEnum.ISSUING.getCode().equals(activity.getState())
                && LitemallActivity.StateEnum.STOP_FORCING.getCode().equals(bState)) {
            activity.setState(bState);
            litemallActivityService.updateActivityById(activity, admin);
        }
        // 目前活动是手动下线，允许发布
        else if (LitemallActivity.StateEnum.STOP_FORCING.getCode().equals(activity.getState())
                && LitemallActivity.StateEnum.ISSUING.getCode().equals(bState)) {
            activity.setState(bState);
            litemallActivityService.updateActivityById(activity, admin);
        }
        // 其他未知情况
        else {
            return ResponseUtil.fail(900, "不允许该操作");
        }
        return ResponseUtil.ok();
    }

    public Object grouponUserList(LitemallActivityGrouponEditVo vo) {
        if (StringUtils.isBlank(vo.getGrouponCode())) {
            return ResponseUtil.fail(900, "团号不能为空");
        }
        Map<String, Object> params = Maps.newConcurrentMap();
        params.put("grouponCode", vo.getGrouponCode());
        params.put("payStates", Collections.singletonList(LitemallActivityGroupon.PayStateEnum.SUCCESS.getCode()));
        List<LitemallActivityGroupon> dbList = activityGrouponService.findByParams(Collections.singletonList(params));
        if (CollectionUtils.isEmpty(dbList)) {
            return Collections.emptyList();
        }
        List<Map<String, Object>> voList = dbList.stream().filter(it -> !it.getGrouponId().equals(0)).map(it -> {
            Map<String, Object> map = Maps.newConcurrentMap();
            map.put("userId", it.getUserId());
            map.put("userName", it.getUserName());
            return map;
        }).collect(Collectors.toList());
        return ResponseUtil.ok(voList);
    }

    public Object changeGroupon(LitemallActivityGrouponEditVo vo, LitemallAdmin admin) {
        if (vo.getId() == null || StringUtils.isBlank(vo.getGrouponCode())) {
            return ResponseUtil.fail(900, "团购信息id和新团号不能为空");
        }
        LitemallActivityGroupon currentGroupon = activityGrouponService.findById(vo.getId());
        if (currentGroupon == null) {
            return ResponseUtil.fail(900, "团购信息id查询信息为空");
        }
        Map<String, Object> sourceGrouponMap = Maps.newConcurrentMap();
        sourceGrouponMap.put("grouponCode", currentGroupon.getGrouponCode());
        sourceGrouponMap.put("payStates", Collections.singletonList(LitemallActivityGroupon.PayStateEnum.SUCCESS.getCode()));
        List<LitemallActivityGroupon> currentGrouponList = activityGrouponService.findByParams(Collections.singletonList(sourceGrouponMap));
        if (CollectionUtils.isEmpty(currentGrouponList)) {
            return ResponseUtil.fail(900, "原团信息查询为空");
        }

        // 已有成员参团，团长不能换团，团员才可以换团；团长可以先降为团员再换团
        if (currentGroupon.getGrouponId().equals(0) && currentGrouponList.size() > 1) {
            return ResponseUtil.fail(900, "团长不能换团，如必须更换团请先尝试更换团长");
        }

        // 查询要换的团，做下面1,2,3判断
        Map<String, Object> targetGrouponMap = Maps.newConcurrentMap();
        targetGrouponMap.put("grouponCode", vo.getGrouponCode());
        targetGrouponMap.put("payStates", Collections.singletonList(LitemallActivityGroupon.PayStateEnum.SUCCESS.getCode()));
        List<LitemallActivityGroupon> targetGrouponList = activityGrouponService.findByParams(Collections.singletonList(targetGrouponMap));
        if (CollectionUtils.isEmpty(targetGrouponList)) {
            return ResponseUtil.fail(900, "目标的团信息查询不到");
        }

        Integer targetActivityId = targetGrouponList.get(0).getActivityId();
        Integer targetSubjectId = targetGrouponList.get(0).getSubjectId();

        // 1.要换的目的团，必须是相同活动id
        if (!currentGroupon.getActivityId().equals(targetActivityId)) {
            return ResponseUtil.fail(900, String.format("必须是相同活动[%s]的拼团商品[%s]",
                    currentGroupon.getActivityId(), currentGroupon.getSubject()));
        }

        Map<String, Object> ruleMap = Maps.newConcurrentMap();
        ruleMap.put("activityId", targetActivityId);
        ruleMap.put("subjectId", targetSubjectId);
        List<LitemallActivityRules> ruleList = litemallActivityRulesService.findByParam(Collections.singletonList(ruleMap));
        if (CollectionUtils.isEmpty(ruleList)) {
            return ResponseUtil.fail(900, "活动规则配置异常");
        }
        Integer limited = ruleList
                .stream()
                .map(LitemallActivityRules::getLimited)
                .max((k1, k2) -> k1.compareTo(k2) > 0 ? k1 : k2)
                .get();

        // 2.要换的团人数已是团规则上限，换团失败
        if (targetGrouponList.size() == limited) {
            return ResponseUtil.fail(900, "目标的团已满员");
        }

        // 3.查询要换的团的团长
        LitemallActivityGroupon targetGrouponCaptain = targetGrouponList
                .stream()
                .filter(it -> it.getGrouponId().equals(0))
                .findFirst()
                .orElse(null);
        if (targetGrouponCaptain == null) {
            return ResponseUtil.fail(900, String.format("目标团[%s]没有团长，请先设置团长", vo.getGrouponCode()));
        }

        // 团中只有一人（即团长）可换团；或是团员可换团
        currentGroupon.setGrouponCode(targetGrouponCaptain.getGrouponCode());
        currentGroupon.setGrouponId(targetGrouponCaptain.getId());
        currentGroupon.setUpdatedBy(admin.getUsername());
        activityGrouponService.updateById(currentGroupon);
        return ResponseUtil.ok();
    }

    public Object listActivityGroupon(LitemallActivityGrouponEditVo vo) {
        if (vo.getId() == null) {
            return ResponseUtil.fail(900, "团购信息id不能为空");
        }
        LitemallActivityGroupon currentGroupon = activityGrouponService.findById(vo.getId());
        if (currentGroupon == null) {
            return ResponseUtil.fail(900, "团购信息id查询信息为空");
        }
        Map<String, Object> sourceGrouponMap = Maps.newConcurrentMap();
        sourceGrouponMap.put("activityId", currentGroupon.getActivityId());
        //sourceGrouponMap.put("subjectId", currentGroupon.getSubjectId());
        sourceGrouponMap.put("payStates", Collections.singletonList(LitemallActivityGroupon.PayStateEnum.SUCCESS.getCode()));
        List<LitemallActivityGroupon> activityGrouponList = activityGrouponService.findByParams(Collections.singletonList(sourceGrouponMap));
        if (CollectionUtils.isEmpty(activityGrouponList)) {
            return ResponseUtil.fail(900, "查询活动的所有团信息为空");
        }

        Map<String, Long> gourponCountMap = activityGrouponList
                .stream()
                .collect(Collectors.groupingBy(LitemallActivityGroupon::getGrouponCode, Collectors.counting()));

        Map<String, String> captainMap = activityGrouponList
                .stream()
                .filter(it -> it.getGrouponId().equals(0))
                .collect(Collectors.toMap(LitemallActivityGroupon::getGrouponCode, LitemallActivityGroupon::getContactName));
        Map<String, Object> ruleMap = Maps.newConcurrentMap();
        ruleMap.put("activityId", currentGroupon.getActivityId());
        ruleMap.put("subjectId", currentGroupon.getSubjectId());
        List<LitemallActivityRules> ruleList = litemallActivityRulesService.findByParam(Collections.singletonList(ruleMap));
        if (CollectionUtils.isEmpty(ruleList)) {
            return ResponseUtil.fail(900, "活动规则配置异常");
        }
        Integer limited = ruleList
                .stream()
                .map(LitemallActivityRules::getLimited)
                .max((k1, k2) -> k1.compareTo(k2) > 0 ? k1 : k2)
                .get();

        // 不返回改用户的本团信息
        List<Map<String, Object>> voList = activityGrouponList
                .stream()
                .filter(it -> !it.getGrouponCode().equals(currentGroupon.getGrouponCode()))
                .filter(CommonUtils.distinctByKey(LitemallActivityGroupon::getGrouponCode))
                .map(it -> {
                    Map<String, Object> map = Maps.newConcurrentMap();
                    map.put("grouponCode", it.getGrouponCode());
                    int currentCount = gourponCountMap.getOrDefault(it.getGrouponCode(), 0L).intValue();
                    String desc = currentCount == limited ?
                            String.format("团长%s，团号%s，已满员", captainMap.get(it.getGrouponCode()), it.getGrouponCode())
                            :
                            String.format("团长%s，团号%s，满员为%s人，目前有%s人", captainMap.get(it.getGrouponCode()), it.getGrouponCode(), limited, currentCount);
                    map.put("desc", desc);
                    return map;
                }).collect(Collectors.toList());
        return ResponseUtil.ok(voList);
    }

    @Transactional
    public Object replaceCaptain(LitemallActivityGrouponEditVo vo, LitemallAdmin admin) {
        if (vo.getId() == null || vo.getUserId() == null) {
            return ResponseUtil.fail(900, "团购信息id和新团长的用户id不能为空");
        }
        LitemallActivityGroupon currentGroupon = activityGrouponService.findById(vo.getId());
        if (currentGroupon == null) {
            return ResponseUtil.fail(900, "团购信息id查询信息为空");
        }

        if (!currentGroupon.getGrouponId().equals(0)) {
            return ResponseUtil.fail(900, "替换方必须是团长");
        }

        // fixme: 老学员能否做团员
        //if(LitemallActivityGroupon.UserTypeEnum.OLD.getCode().equals(currentGroupon.getUserType())) {
        //    return ResponseUtil.fail(900, "老学员不能成为团员");
        //}

        Map<String, Object> sourceGrouponMap = Maps.newConcurrentMap();
        sourceGrouponMap.put("grouponCode", currentGroupon.getGrouponCode());
        sourceGrouponMap.put("payStates", Collections.singletonList(LitemallActivityGroupon.PayStateEnum.SUCCESS.getCode()));
        List<LitemallActivityGroupon> currentGrouponList = activityGrouponService.findByParams(Collections.singletonList(sourceGrouponMap));
        if (CollectionUtils.isEmpty(currentGrouponList)) {
            return ResponseUtil.fail(900, "原团信息查询为空");
        }
        if (currentGrouponList.size() <= 1) {
            return ResponseUtil.fail(900, "该团暂无参与成功的团员，操作失败");
        }

        // 被替换的目标用户
        LitemallActivityGroupon targetUser = currentGrouponList
                .stream()
                .filter(it -> it.getUserId().equals(vo.getUserId().toString()))
                .findFirst().orElse(null);

        if (targetUser == null) {
            return ResponseUtil.fail(900, "目标替换为团长的成员不存在于该团");
        }

        // 被替换的目标用户，grouponId设置为0
        // 该团其他用户，grouponId设置为targetUser的id
        for (LitemallActivityGroupon groupon : currentGrouponList) {
            if (groupon.getId().equals(targetUser.getId())) {
                groupon.setGrouponId(0);
            } else {
                groupon.setGrouponId(targetUser.getId());
            }
            groupon.setUpdatedBy(admin.getUsername());
            activityGrouponService.updateById(groupon);
        }
        return ResponseUtil.ok();
    }

    public Object changeUserType(LitemallActivityGrouponEditVo vo, LitemallAdmin admin) {
        if (vo.getId() == null || vo.getUserType() == null) {
            return ResponseUtil.fail(900, "团购信息id和userType不能为空");
        }
        LitemallActivityGroupon currentGroupon = activityGrouponService.findById(vo.getId());
        if (currentGroupon == null) {
            return ResponseUtil.fail(900, "团购信息id查询信息为空");
        }

        if (currentGroupon.getUserType().equals(vo.getUserType())) {
            return ResponseUtil.fail(900,
                    String.format("该用户已经是[%s]",
                            LitemallActivityGroupon.UserTypeEnum.fromCode(currentGroupon.getUserType()).getDesc()));
        }

        currentGroupon.setUserType(vo.getUserType());
        activityGrouponService.updateById(currentGroupon);
        return ResponseUtil.ok();
    }

    public Object independent(LitemallActivityGrouponEditVo vo) {
        if (vo.getId() == null) {
            return ResponseUtil.fail(900, "团购信息id不能为空");
        }
        LitemallActivityGroupon currentGroupon = activityGrouponService.findById(vo.getId());
        if (currentGroupon == null) {
            return ResponseUtil.fail(900, "团购信息id查询信息为空");
        }
        currentGroupon.setGrouponCode(noGenerator.genActNo(TransNoEnum.AGC));
        currentGroupon.setGrouponId(0);
        activityGrouponService.updateById(currentGroupon);
        return ResponseUtil.ok();
    }

    private void buildActivity(LitemallActivity activity, LitemallActivityCreateVo vo) {
        activity.setType(vo.getType());
        activity.setTitle(vo.getTitle());
        activity.setPosterTitle(vo.getPosterTitle());
        activity.setShareTitle(vo.getShareTitle());
        activity.setStartTime(vo.getStartTime());
        activity.setEndTime(vo.getEndTime());
        activity.setMusicUrl(vo.getMusicUrl());
        activity.setState(Byte.valueOf(vo.getState()));
        activity.setDeleted(LitemallActivity.NOT_DELETED);
    }

    private LitemallActivityPic buildPic(String url, Integer activityId, Byte type) {
        LitemallActivityPic pic = new LitemallActivityPic();
        pic.setType(type);
        pic.setDeleted(LitemallActivityPic.NOT_DELETED);
        pic.setActivityId(activityId);
        pic.setPicUrl(url);
        return pic;
    }

    private LitemallActivityContent buildContent(Integer activityId, String content, Byte type) {
        LitemallActivityContent entity = new LitemallActivityContent();
        entity.setActivityId(activityId);
        entity.setContent(content);
        entity.setType(type);
        return entity;
    }

}
